#include "fmemory.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <errno.h>

#define BITSHIFT 16

static FILE *memory_mapped_file = NULL;
static long memnum = 0;

void *alloc(size_t size) {
  void *ptr = NULL;

  if(memory_mapped_file == NULL) {
    if((memory_mapped_file = fopen("$MEMORY", "w+")) == NULL) return NULL;
  } else if(ftell(memory_mapped_file) > 1L << BITSHIFT) { //We would overwrite...
    errno = EFAULT;
    return NULL;
  }
  ++memnum; //Get next...
  ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(memory_mapped_file), memnum << BITSHIFT);
  fwrite(&ptr, sizeof(ptr), 1, memory_mapped_file);
  fwrite(&size, sizeof(size), 1, memory_mapped_file);
  memnum += size >> BITSHIFT;
  ftruncate(fileno(memory_mapped_file), (memnum + 1) << BITSHIFT);
  if(ptr == NULL) errno = ENOMEM;
  return ptr;
}

void ffree(void *ptr) {
  long i, pos;
  void *allocated;
  size_t size;

  pos = ftell(memory_mapped_file);
  rewind(memory_mapped_file);
  for(i = 0; i < memnum; ++i) {
    fread(&allocated, sizeof(allocated), 1, memory_mapped_file);
    fread(&size, sizeof(size), 1, memory_mapped_file);
    if(allocated == ptr) {
      printf("freeing %p\n", ptr);
      munmap(ptr, size); /* We do not need to check for double free as
			    "It is not an error if the indicated range
			    does not contain any mapped pages". */
      goto end;
    }
  }
  fprintf(stderr, "Unknown free at %p\n", ptr);
  abort();
 end:
  fseek(memory_mapped_file, 0, SEEK_SET);
}

int main() {
  long *lp;
  short *sp;
  int i;
  char *cp;

  lp = alloc(sizeof(long) * 100);
  printf("lp = %p\n", lp);
  lp[0] = 0xdeadbeef;
  lp[99]= 0xcafecafe;
  lp = alloc(sizeof(long) * 40000);
  lp[0] = -1;
  lp[39999] = -1;
  printf("lp = %p\n", lp);
  sp = alloc(sizeof(short) * 256);
  printf("sp = %p\n", sp);
  for(i = 0; i < 256; ++i) sp[i] = i * 7;
  cp = alloc(sizeof(char) * 256);
  printf("cp = %p\n", cp);
  for(i = 0; i < 256; ++i) cp[i] = i;
  ffree(lp);
  //ffree(lp - 99);
  ffree(lp);
  return 0;
}
